package chen.yi.component.idempotent.aspect;

import chen.yi.component.idempotent.annotate.RepeatSubmit;
import chen.yi.component.idempotent.constant.RedisKey;
import chen.yi.component.idempotent.sign.SignInterface;
import chen.yi.component.redis.utils.RedisUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 基于注解防止重复提交
 *
 * @author huat
 **/
@Aspect
public class AnnotateRepeatAspect {
    private final SignInterface signInterface;

    public AnnotateRepeatAspect(SignInterface signInterface) {
        this.signInterface = signInterface;
    }

    /**
     * 注解切面
     */
    @Pointcut("@annotation(chen.yi.component.idempotent.annotate.RepeatSubmit)")
    public void aspect() {

    }


    /**
     * 切面 环绕增强
     *
     * @param joinPoint
     */
    @Around("aspect()")
    public Object  aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        //获取操作
        RepeatSubmit repeatSubmit = method.getAnnotation(RepeatSubmit.class);
        //获取requestAttributes
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // 获取请求上下文
        HttpServletRequest request = requestAttributes.getRequest();

        //redis key
        String key = RedisKey.REPEAT_KEY + signInterface.getUserSign(request) + ":" + request.getRequestURI();
        Object o = RedisUtil.get(key);
        //最小间隔时间
        long interval = repeatSubmit.interval();
        //判断是否为空
        //判断最后操作时间距离现在时间是否超过配置最小请求时间
        if (!Objects.isNull(o) && System.currentTimeMillis() - Long.parseLong(o.toString()) < interval) {
            HttpServletResponse response = requestAttributes.getResponse();
            PrintWriter writer =null;
            try {
              response.setContentType("application/json");
              response.setCharacterEncoding("UTF-8");
              writer = response.getWriter();
              writer.write("{\"code\":500,\"message\":\""+repeatSubmit.message()+"\"}");
              writer.flush();
          }finally {
              if (Objects.nonNull(writer)) {
                  writer.close();
              }
          }
            return null;
        }
        RedisUtil.set(key, System.currentTimeMillis(), interval, TimeUnit.MILLISECONDS);
        return joinPoint.proceed();
    }
}
